import "./global/index.js";
import path from "path";
import fs from "fs";
import express from "express";

import { Controller, Service } from "./core/index.js";
import {
  log,
  setCookie,
  setFavicon,
  setBody,
  setStatic,
  setHeader,
  setTemplate,
  Cors,
  validator,
  waf,
} from "./middleware/index.js";
import { db, loaderSort, loadConfig } from "./helper/index.js";
import {dirname} from "./helper/file.js";

class Chan {
  //版本号
  #version = "0.0.0";
  static helper = {};
  static common = {}; //公共方法
  static config = {}; //配置
  static Service = Service; //服务
  static Controller = Controller; //控制器
  static extend = {}; //组件扩展
  static middleware = {}; //中间件

  constructor() {
    this.app = express();
    this.router = express.Router();
  }

  beforeStart(cb) {
    cb && cb();
  }

  async init() {
    await this.config();
    await this.loadExtend(); //utils
    this.loadMiddleware();
    this.loadDB();
  }

  //加载配置文件
  async config() {
    let config = await loadConfig();
    Chan.config = config;
  }

  //加载中间件
  async loadMiddleware() {
    const {
      views,
      env,
      APP_NAME,
      APP_VERSION,
      cookieKey,
      BODY_LIMIT,
      statics,
      logger,
      cors,
    } = Chan.config;
    
    this.app.set('trust proxy', true);
    log(this.app, logger);
    setFavicon(this.app);
    setCookie(this.app, cookieKey);
    setBody(this.app, BODY_LIMIT);
    waf(this.app);
    setTemplate(this.app, { views, env });
    setStatic(this.app, statics);
    Cors(this.app, cors);
    setHeader(this.app, { APP_NAME, APP_VERSION });
  }

  //数据库操作
  loadDB() {
    if (Chan.config?.db?.length > 0) {
      Chan.config.db.map((item, index) => {
        if (index == 0) {
          Chan.knex = db(item);
        } else {
          Chan[`knex${index}`] = db(item);
        }
      });
    }
  }

  async loadRouter() {
    const configPath = path.join(APP_PATH, "modules");
    if (fs.existsSync(configPath)) {
      const dirs = loaderSort(Chan.config.modules);
      for (const item of dirs) {
        let router = await importFile(`app/modules/${item}/router.js`);
        router(this.app, this.router, Chan.config);
      }
    }
  }

  //通用路由，加载错误处理和500路由和爬虫处理
  async loadCommonRouter() {
    try {
      let router = await importFile("app/router.js");
      router(this.app, this.router, Chan.config);
    } catch (error) {
      console.log(error);
    }
  }

  async loadExtend() {
    let arr = [
      {
        _path: COMMON_PATH,
        key: "common",
      },
      {
        _path: HELPER_PATH,
        key: "helper",
      },
      {
        _path: path.join(dirname(import.meta.url), "helper"),
        key: "helper",
      },
    ];
    for (let item of arr) {
      await this.loadFn(item._path, item.key);
    }
  }

  async loadFn(_path, key) {
    if (fs.existsSync(_path)) {
      const files = fs.readdirSync(_path).filter((file) => file.endsWith(".js"));
      for (const file of files) {
        const filePath = path.join(_path, file);
        let helperModule = await importFile(filePath);
        // Chan.common[file.replace(".js", "")] = helperModule;
        // 将模块导出的所有方法/属性，直接混入到 Chan.common 上
        Object.assign(Chan[key], helperModule);
      }
    }
  }

  async start(cb) {
    await this.init();
    await this.loadRouter();
    await this.loadCommonRouter();

    cb && cb();
  }

  getAllRouter() {
    // 获取所有路径
    const routes = this.router.stack
      .filter((r) => r.route) // 过滤掉中间件
      .map((r) => ({
        path: r.route.path,
        methods: Object.keys(r.route.methods),
      }));

    console.log(routes);
  }

  run(cb) {
    const port = parseInt(process.env.PORT) || 3000;
    this.app.listen(port, () => {
      cb ? cb(port) : console.log(`Server is running on port ${port}`);
    });
  }
}

global.Chan = Chan;
export default Chan;
